﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace RayTracing
{
    public class Sphere : Geometry
    {
        P3 center;                //Center of sphere
        P3 Vn = new P3(0, 0, 1);  //Direction of the North Pole
        P3 Ve = new P3(1, 0, 0);  //Direction of the Equator
        P3 hpr = new P3(0, 0, 0); //Heading, Pitch, Roll
        float radius;             //Radius of sphere

        public Sphere(P3 center, float radius)              //Simple Constructor uses only center and radius
        {
            this.center = center;
            this.radius = radius;
        }

        public Sphere(P3 center, float radius,P3 Vn, P3 Ve) //Uses Vn and Ve along with center and radius 
        {
            this.center = center;
            this.radius = radius;
            this.Vn = Vn;
            this.Ve = Ve;
        }

        public Sphere(P3 center, float radius, P3 hpr)      //Complex Constructor uses hpr along with center and radius
        {
            this.center = center;
            this.radius = radius;
            this.hpr = hpr;
        }

        #region Geometry Members

        public P3 normal(P3 p)
        {
            return new P3(P3.scale(P3.sub(p, this.center), 1 / radius));
        }

        public float distance(Ray ray)
        {
            P3 E = ray.origin;
            P3 O = this.center;
            P3 EO = P3.sub(O, E);
            P3 V = ray.direction;
            float r = this.radius;

            float v = P3.dot(EO, V);
            float dot = P3.dot(EO, EO);
            float disc = (r * r) - (dot - (v * v));
            if (disc < 0)
            {
                //Console.WriteLine(disc);
                return Main.infinity;
                //            no intersection
            }
            else
            {
                float d = (float)Math.Sqrt(disc);
                float time = (v - d);
                if (time < 0)
                {
                    //Console.WriteLine(time);
                    return Main.infinity;
                }
                else
                {
                    return time;
                }
            }
        }

        public P2 toP2(P3 p)
        {
            P3 Vp = this.normal(p);
            float u;

            float dotProduct = (float) Math.Min(1, Math.Max(-1,-P3.dot(Vn, Vp)));
            float phi = (float)Math.Acos(dotProduct);
            float v = (float)(phi / Math.PI);

            float dotProduct2 =(float) Math.Min(1, Math.Max(-1, P3.dot(Vp, Ve) / Math.Sin(phi)));
            float theta = (float)((Math.Acos( dotProduct2) ) / ( 2 * Math.PI));
            if ( P3.dot( P3.cross( Vn, Ve ), Vp ) > 0 )
            {
                u = theta;
            }
            else
            {
                u = 1 - theta;
            }

            return new P2(u,v);
        }

        #endregion
    }
}
